package com.javaeedev.util;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.type.Type;

import com.javaeedev.exception.ResourceNotFoundException;

/**
 * Defined as a bean used to make hibernate eager init.
 * 
 * @author Xuefeng
 * 
 * @spring.bean id="hibernateUtil"
 */
public class HibernateUtil {

    private static Log log;
    private static final SessionFactory sessionFactory;

    static {
        log = LogFactory.getLog(HibernateUtil.class);
        try {
            sessionFactory = new AnnotationConfiguration()
                                 .configure()
                                 .buildSessionFactory();
        }
        catch(Exception e) {
            e.printStackTrace();
            log.error("Error init SessionFactory.", e);
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * Get current Hibernate session by calling SessionFactory.getCurrentSession().
     */
    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public static Object get(Class clazz, Serializable id) {
        Object o = HibernateUtil.getCurrentSession().get(clazz, id);
        return o;
    }

    @SuppressWarnings("unchecked")
    public static Object query(Class clazz, Serializable id) {
        Object t = get(clazz, id);
        if(t==null)
            throw new ResourceNotFoundException("指定的资源未找到");
        return t;
    }

    public static void createEntity(Object entity) {
        HibernateUtil.getCurrentSession().save(entity);
    }

    public static void updateEntity(Object entity) {
        HibernateUtil.getCurrentSession().update(entity);
    }

    public static void deleteEntity(Object entity) {
        HibernateUtil.getCurrentSession().delete(entity);
    }

    public static Object queryForObject(String hql) {
        return queryForObject(hql, null, null);
    }

    public static Object queryForObject(String hql, Object[] params) {
        return queryForObject(hql, params, null);
    }

    public static Object queryForObject(String hql, Object[] params, Type[] types) {
        Session session = HibernateUtil.getCurrentSession();
        Query query = session.createQuery(hql);
        bindParameters(query, params, types);
        return query.uniqueResult();
    }

    @SuppressWarnings("unchecked")
    public static List queryForList(String hql, Object[] params, Type[] types, int max) {
        return queryForList(hql, params, types, 0, max);
    }

    @SuppressWarnings("unchecked")
    public static List queryForList(String hql, Object[] params, Type[] types, int first, int max) {
        Session session = HibernateUtil.getCurrentSession();
        Query query = session.createQuery(hql);
        bindParameters(query, params, types);
        return query.setFirstResult(first).setMaxResults(max).list();
    }

    @SuppressWarnings("unchecked")
    public static List queryForList(String hql) {
        return queryForList(hql, null, null);
    }

    @SuppressWarnings("unchecked")
    public static List queryForList(String hql, Object[] params) {
        return queryForList(hql, params, null);
    }

    @SuppressWarnings("unchecked")
    public static List queryForList(String hql, Object[] params, Type[] types) {
        Session session = HibernateUtil.getCurrentSession();
        Query query = session.createQuery(hql);
        bindParameters(query, params, types);
        return query.list();
    }

    public static int executeUpdate(String hql) {
        return executeUpdate(hql, null, null);
    }

    public static int executeUpdate(String hql, Object[] params) {
        return executeUpdate(hql, params, null);
    }

    public static int executeUpdate(String hql, Object[] params, Type[] types) {
        Session session = HibernateUtil.getCurrentSession();
        Query query = session.createQuery(hql);
        bindParameters(query, params, types);
        return query.executeUpdate();
    }

    private static void bindParameters(Query query, Object[] params, Type[] types) {
        if(params!=null) {
            if(types==null) {
                for(int i=0; i<params.length; i++) {
                    query.setParameter(i, params[i]);
                }
            }
            else {
                for(int i=0; i<params.length; i++) {
                    query.setParameter(i, params[i], types[i]);
                }
            }
        }
    }

}
